// use log::info;
use http::{request::Builder, Method};
use serde::de::DeserializeOwned;
use yew::services::fetch::{FetchService, Response};
pub use yew::services::fetch::{FetchTask, Request};

pub use yew::format::{Json, Nothing, Text};
pub use yew::Callback;

use failure::{err_msg, Error};

pub type Resp<T> = Result<T, Error>;

pub trait Fetchable {
    fn execute<T: DeserializeOwned + 'static>(
        self,
        handler: Callback<Resp<T>>,
    ) -> Option<FetchTask>;
}

impl<IN: Into<Text>> Fetchable for http::Result<Request<IN>> {
    fn execute<T: DeserializeOwned + 'static>(
        self,
        handler: Callback<Resp<T>>,
    ) -> Option<FetchTask> {
        send_reqeust(self, handler)
    }
}

pub fn get<T: AsRef<str>>(uri: T) -> Builder {
    make_request(Method::GET, uri.as_ref())
}

pub fn post<T: AsRef<str>>(uri: T) -> Builder {
    make_request(Method::POST, uri.as_ref())
}

pub fn put<T: AsRef<str>>(uri: T) -> Builder {
    make_request(Method::PUT, uri.as_ref())
}

pub fn delete<T: AsRef<str>>(uri: T) -> Builder {
    make_request(Method::DELETE, uri.as_ref())
}

pub fn make_request(method: Method, uri: &str) -> Builder {
    let mut builder = Request::builder();
    builder
        .method(method)
        .uri(uri)
        .header("Content-Type", "application/json");
    builder
}

pub fn send_reqeust<IN, T>(
    request: http::Result<Request<IN>>,
    handler: Callback<Resp<T>>,
) -> Option<FetchTask>
where
    T: DeserializeOwned + 'static,
    IN: Into<Text>,
{
    match request {
        Ok(request) => {
            let callback = handler.reform(|response: Response<Json<Resp<T>>>| {
                let (meta, Json(data)) = response.into_parts();
                if meta.status.is_success() {
                    data
                } else {
                    Err(err_msg(meta.status.to_string()))
                }
            });
            Some(FetchService::new().fetch(request, callback))
        }
        Err(err) => {
            handler.emit(Err(Error::from(err)));
            None
        }
    }
}
